package io.gitee.tziye.core.lock;

import io.gitee.tziye.common.Constants;
import io.gitee.tziye.common.RenaiUtil;
import io.gitee.tziye.core.instance.DefaultRenaiClient;
import io.gitee.tziye.jdbc.JdbcProxy;
import io.gitee.tziye.jdbc.ProcedureResult;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

public class DefaultLockOperator extends LockOperator {

    private final JdbcProxy jdbcProxy;

    public DefaultLockOperator(DefaultRenaiClient renaiClient) {
        super(renaiClient);
        jdbcProxy = renaiClient.getJdbcProxy();
    }

    @Override
    public boolean lock(String key, String value, int expireSeconds) {
        assert StringUtils.isNoneBlank(key, value) && expireSeconds > 0;
        return commonLock(key, value, expireSeconds);
    }

    @Override
    public boolean lock(String key, String value, int expireSeconds, int timeout) {
        assert StringUtils.isNoneBlank(key, value) && expireSeconds > 0 && timeout > 0;
        int waitSecond = 0;
        while (waitSecond < timeout) {
            if (commonLock(key, value, expireSeconds)) {
                return true;
            }
            waitSecond++;
            RenaiUtil.sleep(1);
        }
        return false;
    }

    private boolean commonLock(String key, String value, int expireSeconds) {
        Map<String, Object> params = new HashMap<>();
        params.put(Constants.KEY, key);
        params.put(Constants.VALUE, value);
        params.put(Constants.EXPIRE_SECONDS, expireSeconds);
        ProcedureResult result = jdbcProxy.call(Constants.LOCK_LOCK, params);
        return result.updated() > 0;
    }

    @Override
    public boolean unlock(String key, String value) {
        assert StringUtils.isNoneBlank(key, value);
        String sql = "DELETE FROM renai_lock_record WHERE k = ? AND v = ?";
        return jdbcProxy.update(sql, key, value) > 0;
    }

    @Override
    public int delete(Collection<String> keys) {
        assert CollectionUtils.isNotEmpty(keys);
        String sql = "DELETE FROM renai_lock_record WHERE k IN (:keys)";
        Map<String, Object> params = new HashMap<>();
        params.put("keys", keys);
        return jdbcProxy.namedUpdate(sql, params);
    }

}